package com.nickstumpos.android.easyVolume.preset.service;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.codec.binary.Base64;

import android.content.Context;
import android.content.SharedPreferences;
import android.widget.Toast;

import com.nickstumpos.android.easyVolume.constants.EVCONSTANTS;
import com.nickstumpos.android.easyVolume.preset.dto.PresetLevelsDto;
import com.nickstumpos.android.easyVolume.preset.types.PresetIdentifier;
import com.nickstumpos.android.easyVolume.streams.controller.StreamController;
import com.nickstumpos.android.easyVolume.streams.presentation.types.Screen;
import com.nickstumpos.android.easyVolume.streams.types.Stream;
import com.nickstumpos.android.easyVolume.volume.controller.IVolumeController;

public class PresetService {

	private Context																	main;
	private Map<Screen, IVolumeController>					streams;
	private Map<PresetIdentifier, PresetLevelsDto>	presets;
	private SharedPreferences												settings;
	private SharedPreferences.Editor								editor;
	private StreamController												streamController;

	public PresetService(Context main) {
		super();
		this.streamController = new StreamController(main);
		this.main = main;
		this.streams = new HashMap<Screen, IVolumeController>();
		this.setupSavedPrefs(main);
		this.setupPresetMap();
	}

	public void applyPreset(PresetIdentifier number) {
		PresetLevelsDto preset = this.presets.get(number);
		for (Stream stream : Stream.values()) {
			this.streamController.setStreamVolumeLevel(preset.getLevel(stream),
					stream);
			if (preset.getVibe(stream) != null) {
				this.streamController.setVibrate(preset.getVibe(stream), stream);
			}
		}
		if (!this.streams.isEmpty()) {
			for (Screen screen : Screen.values()) {
				if (!screen.equals(Screen.MASTER)) {
					if (preset.getIsSlave(screen)) {
						this.streams.get(screen).setAsSlave();
					} else {
						this.streams.get(screen).setNotSlave();
					}
					this.streams.get(screen).refresh();
				}
			}
			this.streams.get(Screen.MASTER).refresh();
		}
		Toast.makeText(this.main,
				"Preset \"" + this.getPresetTitle(number) + "\" applied",
				Toast.LENGTH_SHORT).show();
	}

	public String getPresetTitle(PresetIdentifier preset) {
		String title = null;
		if (preset != null) {
			switch (preset) {
				case ONE:
					title = this.settings.getString(EVCONSTANTS.ONE_NAME, preset
							.getName());
					break;
				case TWO:
					title = this.settings.getString(EVCONSTANTS.TWO_NAME, preset
							.getName());
					break;
				case THREE:
					title = this.settings.getString(EVCONSTANTS.THREE_NAME, preset
							.getName());
					break;
				case FOUR:
					title = this.settings.getString(EVCONSTANTS.FOUR_NAME, preset
							.getName());
					break;
				case FIVE:
					title = this.settings.getString(EVCONSTANTS.FIVE_NAME, preset
							.getName());
					break;
				case SIX:
					title = this.settings.getString(EVCONSTANTS.SIX_NAME, preset
							.getName());
					break;
				default:
					title = preset.getName();
			}
		}
		return title;
	}

	/**
	 * @return the streams
	 */
	public Map<Screen, IVolumeController> getStreams() {
		return this.streams;
	}

	public boolean isSet(PresetIdentifier pi) {
		return this.presets.get(pi).isSet();
	}

	public void setPreset(PresetIdentifier number) {
		PresetLevelsDto preset = this.presets.get(number);
		for (Stream stream : Stream.values()) {
			preset.setLevel(stream, this.streamController
					.getCurrentVolumeLevel(stream));
		}
		for (Screen screen : Screen.values()) {
			preset.setIsSlave(screen, this.streams.get(screen).isSlave());
		}
		preset.setSet(true);
		final Base64 encoder = new Base64();
		final ByteArrayOutputStream bos = new ByteArrayOutputStream();
		ObjectOutputStream out = null;
		try {
			out = new ObjectOutputStream(bos);
			out.writeObject(preset);
			out.close();
			final byte[] byteParameter = encoder.encode(bos.toByteArray());
			String serialParameter = new String(byteParameter);
			serialParameter = serialParameter.replace("\n", "");
			serialParameter = serialParameter.replace("\r", "");
			this.editor.putString(number.getName(), serialParameter);
			this.editor.commit();
			Toast.makeText(this.main,
					"Preset \"" + this.getPresetTitle(number) + "\" saved",
					Toast.LENGTH_SHORT).show();
		} catch (final IOException e) {
			Toast.makeText(this.main,
					"Saving preset \"" + this.getPresetTitle(number) + "\" failed",
					Toast.LENGTH_SHORT).show();
		}
		setupPresetMap();

	}

	private void setupPresetMap() {
		this.presets = new HashMap<PresetIdentifier, PresetLevelsDto>();
		for (PresetIdentifier preset : PresetIdentifier.values()) {
			String presetObject = this.settings.getString(preset.getName(), null);
			if (presetObject != null) {
				final byte[] buf = Base64.decodeBase64(presetObject.getBytes());
				ObjectInputStream in = null;
				try {
					in = new ObjectInputStream(new ByteArrayInputStream(buf));
					PresetLevelsDto inflated = (PresetLevelsDto) in.readObject();
					inflated.setSet(true);
					this.presets.put(preset, inflated);
				} catch (final IOException e) {
				} catch (final ClassNotFoundException e) {
				}
			} else {
				PresetLevelsDto pdto = new PresetLevelsDto();
				pdto.setSet(false);
				this.presets.put(preset, new PresetLevelsDto());
			}
		}

	}

	private void setupSavedPrefs(Context context) {
		this.settings = context.getSharedPreferences(EVCONSTANTS.PREFS_NAME, 0);
		this.editor = this.settings.edit();
	}
}
